/* ********************************************************************************
 * *      Copyright:  (C) 2019 Wu Yujun<540726307@qq.com>
 * *                  All rights reserved.
 * *
 * *       Filename:  server_socket.c
 * *    Description:  This file is init server socket 
 * *                 
 * *        Version:  1.0.0(2019年06月07日)
 * *         Author:  Wu Yujun <540726307@qq.com>
 * *      ChangeLog:  1, Release initial version on "2019年06月07日 15时46分42秒"
 * *                 
 * ********************************************************************************/

#include "server_socket.h"

/********************************************************************************************************
 * 描述：    创建初始化服务器套接字                                                                     *
 *                                                                                                      *
 * 参数：    char *lis_addr监听的IP地址字符串"x.x.x.x",如果传NULL则监听所有网卡IP地址htonl(INADDR_ANY) ;*
 *           int port指定监听的端口 .                                                                   *
 *                                                                                                      *
 * 返回值：                                                                                             *
 *          成功返回socket文件描述符                                                                    *
 *          失败返回负数                                                                                *
 *******************************************************************************************************/
int creat_socket(char *lis_addr, int port) //socket()、bind()、listen() 
{
    int                     serv_fd ;
    struct sockaddr_in      serv_addr ;
    int                     reval = 0 ;
                            
    serv_fd= socket(AF_INET, SOCK_STREAM, 0) ;
    if(serv_fd < 0)
    {
        printf("socket() failed: %s\n", strerror(errno));
        return  ERROR ;
    }
    
    memset(&serv_addr, 0, sizeof(serv_addr)) ;
    serv_addr.sin_family = AF_INET ;
    serv_addr.sin_port = htons(port) ;
    if(!lis_addr)
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
    else 
        inet_aton(lis_addr, &serv_addr.sin_addr) ;
                                                     
    int reuse = 1 ;
    setsockopt(serv_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); //reuseaddr
    if( bind(serv_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ) < 0)
    {
        printf("bind() failed: %s\n", strerror(errno)) ;
        reval = -1 ;
        
        goto cleanup ;
    }

    if(listen(serv_fd, BACK_LOG) < 0)
    {
        printf("listen() failed: %s\n", strerror(errno));
        reval = -2 ;
        
        goto cleanup ;
    }
    
cleanup:
    if(reval < 0)
    {   
        close(serv_fd) ;
        return ERROR ;
    }
    else
        return serv_fd ;
}

/**************************************************************
 * 描述： 接受新的客户端
 *
 * 参数：   int listen_fd传的服务器socket对应的文件描述符
 *
 * 返回值： 
 *          成功返回接收到的客户端文件描述符
 *          失败返回负数.
 ************************************************************ */

int accept_client(int listen_fd) //accept new client
{
    int                     client_fd ;
    struct sockaddr_in      cli_addr ;
    socklen_t               cli_addr_len = 0 ; //桟中的局部变量是随机值，如果随机到负数accept会出错
    memset(&cli_addr, 0, sizeof(cli_addr)) ;
    client_fd = accept(listen_fd,(struct sockaddr*)&cli_addr, &cli_addr_len) ;//block untill a new client connect 
    if(client_fd < 0)
    {
        printf("accept failure: %s\n", strerror(errno)) ;
        return ERROR ;
    }
    printf("accept sucessful, client [%s:%d] \n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port) ) ;
    return client_fd ; 
}

